#ifndef DIRECTION
#define DIRECTION
#include <iostream>
#include <map>
#include "../../base/TemplateParser/Function.h"
#include "../../base/TemplateParser/Condition.h"
#include "../../base/TemplateParser/Operation.h"
using namespace std;
class Direction:public Function, public Operation, public Condition
{
	public:
	virtual string parse(string)=0;
	virtual string getViewData(string)=0;
	virtual boost::any getViewAnyData(string)=0;
		bool isFunction(string in){return Function::isFunction(in);}
		string parseFunction(string in){return Function::parseFunction(in);}
		bool isOperation(string in){return Operation::isOperation(in);}
		string parseOperation(string in){return Operation::parseOperation(in);}
		bool isCondition(string in){return Condition::isCondition(in);}
		bool parseCondition(string in){return Condition::parseCondition(in);}
		string parseDirection(string, string);
		bool isDirection(string);
	private:
		string _IF(string, string);
		string _WHILE(string, string);
		string _FOR(string, string);
		string _FOREACH(string, string);

 };
bool Direction::isDirection(string dir){
	dir=Function::getDirection(dir);
	return dir=="if" || dir=="while" || dir=="for" || dir=="foreach";
}
string Direction::parseDirection(string dir, string content){
	//parse dirname and condition
	string dirname;
	string condition;
	string::size_type pos=dir.find_first_of('(');
	if(pos!=string::npos){
		dirname=dir.substr(0,pos);
		pos++;
		condition=dir.substr(pos,dir.size()-pos-1);
	}
	else throw "expected ( in " + dir;
	if(dirname=="if")return _IF(condition, content);
	if(dirname=="while")return _WHILE(condition, content);
	if(dirname=="for")return _FOR(condition, content);
	if(dirname=="foreach")return _FOREACH(condition, content);
	return "";
}


string Direction::_FOREACH(string condition, string content)
{
	string rt="";
	vector<string> cond=StringProcessor::explode(";",condition);

	if(cond.size()<3)throw "not enough variable in foreach";
	string var1=cond.at(0);
	string var2=cond.at(1);
	string var3=cond.at(2);
	//get array
	map<string,boost::any> arr;
	try {
		arr=boost::any_cast<map<string,boost::any> >(getViewAnyData(var1));
	}
	catch(...){
		throw var1 + " is not an array in foreach";
	}
	map<string,boost::any>::iterator it;

	for ( it=arr.begin() ; it != arr.end(); it++ ){
		ViewData[var2]=(*it).first;
		ViewData[var3]=(*it).second;
		rt+=parse(content);
	}

	return rt;
}

string Direction::_FOR(string condition, string content)
{
	string rt="";
	vector<string> cond=StringProcessor::explode(";",condition);
	//cout<<cond.size()<<endl;
	if(cond.size()<3)throw "not enough condtion or operation in for";
	string op1=cond.at(0);
	string cd=cond.at(1);
	string op2=cond.at(2);
	//if cond==true then
	//init op1:
	//cout<<op1+";"+cd+";"+op2+";"<<endl;
	parseOperation(op1);
	while(parseCondition(cd)){
		//parse block_content:
		rt+=parse(content);
		parseOperation(op2);
	}
	return rt;
}

string Direction::_WHILE(string condition, string content)
{
	string rt="";
	//if cond==true then
	while(parseCondition(condition)){
		//parse block_content:
		rt+=parse(content);
	}
	return rt;
}

string Direction::_IF(string condition, string content)
{
	//get block content
	string block_content="";
	string else_block_content="";
	string::size_type pos=content.find_first_of('{');
	if(pos==string::npos)throw "expected { in IF";
	pos++;
	string::size_type posstart=pos;
	string::iterator it=content.begin()+pos;
	int openbracket=1;
	while(it!=content.end()){
		if(*it=='{')openbracket++;
		else if(*it=='}')openbracket--;
		if(openbracket==0){
			block_content=content.substr(posstart,pos-posstart);
			break;
		}
		it++;
		pos++;
	}

	//check else, else if
	it++;
	pos++;
	string::size_type pos2=string::npos;
	if(it!=content.end()){
		pos2=content.find_first_of('@',pos);
		if(pos2!=string::npos){
			if(content.substr(pos2,7)=="@elseif"){
				pos2+=5;
				else_block_content="@"+content.substr(pos2,content.size()-pos2);
			}
			//==@else
			else{
				pos2=content.find_first_of('{',pos2);
				pos2++;
				else_block_content=content.substr(pos2,content.size()-pos2-1);
			}
		}
	}

	if(parseCondition(condition)){
		//parse block_content:
		//cout<<content<<endl;
		return parse(block_content);
	}
	else if(else_block_content!=""){
		return parse(else_block_content);
	}
	//check else or else if
	return "";

}
/*
void Direction::parseDirection(parseitem &dir){
        	TemplateParser::BO::parsedirection di;
    		using boost::spirit::ascii::space;
    		//cout<<dir.direction<<endl;
    		//cerr<<dir.in<<endl;
    		if(dir.direction==TemplateParser::Direction::IF){
    			qiparser::DirectionProcess::_IF(dir);
    		}
    		else if(dir.direction==TemplateParser::Direction::WHILE){
    			qiparser::DirectionProcess::_WHILE(dir);
    		}
    		else if(dir.direction==TemplateParser::Direction::FOR){
				qiparser::DirectionProcess::_FOR(dir);
			}
    		else if(dir.direction.at(0)=='@'){
    			dir.out+=dir.direction;
    		}
    		else{

    			//is parse equal operation
    			if(parseEqualOperation(dir.direction,dir.in)){
    				//cout<<dir.out<<'-'<<dir.in<<endl;
    			}
    			else{
    				//else if is a function
    				if(dir.in.at(0)=='('){
    					//get the param:
    					string::size_type pos=1;
    					string::iterator it = dir.in.begin()+1;
						int open_bracket_count=0;
						while(it!=dir.in.end()){
							if(*it=='(')open_bracket_count++;
							else if(*it==')')open_bracket_count--;
							if(open_bracket_count<0)break;
							it++;
							pos++;
						}
						//meet the close bracker, get param and parse function
						if(it!=dir.in.end()){
							string param;
							param=dir.in.substr(0,pos+1);
							dir.in=dir.in.substr(pos+1,dir.in.size()-pos-1);
							//parse function
							//cerr<<dir.direction<<endl<<dir.in<<endl;
							string strout;
							parsestringfunction(dir.direction,param,strout);
							dir.out+=strout;
						}
						else{
							//throw error
							cerr<<"expected ) in " + dir.direction + " function"<<endl;
						}

    				}
    				//echo direction as variable
    				else{
    					dir.out+=qiparser::getViewData(dir.direction);
    				}
    			}
    		}

        }

void parseBlockNCondition(TemplateParser::BO::parsedirection &in){
			//get pos of {
			string::size_type open_block_pos=in.in.find_first_of('{');
			if(open_block_pos==string::npos){
				//throw error
				throw "expected {";
			}
			//get (condtion content)
			string cond_content;
			cond_content=in.in.substr(0,open_block_pos);

			//get {block content}
			string::size_type end_block_pos=open_block_pos;
			string block_content;
			int count_open_block=0;
			int count_close_block=0;
			string::iterator it = in.in.begin();
			it+=open_block_pos;

			while(it!=in.in.end()){
				if(*it=='{')count_open_block++;
				else if(*it=='}')count_close_block++;
				if(count_open_block!=0 && count_open_block==count_close_block)break;
				it++;
				end_block_pos++;
			}
			//if not enough close } then
			if(it==in.in.end()){
				//throw err
				throw "expected }";
			}
			block_content=in.in.substr(open_block_pos+1,end_block_pos-open_block_pos-1);
			in.out=block_content;
			in.direction=cond_content;
			in.in=in.in.substr(end_block_pos+1,in.in.size()-end_block_pos);

		}
        void _IF(TemplateParser::BO::parsedirection &dir)
        {
        	TemplateParser::BO::parsedirection pcond;
        	pcond.in=dir.in;
        	parseBlockNCondition(pcond);
        	dir.in=pcond.in;
        	string cond_content=pcond.direction;
        	string block_content=pcond.out;
			//if cond==true then
        	//cout<<pcond.in<<endl;
			if(qiparser::parsecondition(qiparser::removespace(cond_content))){
				//parse block_content:
				block_content=qiparser::parsehtml(block_content);
				//output content
				dir.out+=block_content;
			}
			//check else or else if
			pcond.out="";
			pcond.direction="";
			pcond.in="";
			cout<<pcond.in<<endl;
			qigrammar::else_grammar<string::const_iterator> g;
			if(grammarparse(dir.in,g, pcond)){
				//have else
				//parseBlockNCondition(pcond);
				cout<<pcond.out<<"-"<<pcond.direction<<"-"<<pcond.in<<endl;

				//dir.in=pcond.in;
			}

        }

        void _WHILE(TemplateParser::BO::parsedirection &dir)
		{
        	TemplateParser::BO::parsedirection pcond;
			pcond.in=dir.in;
			parseBlockNCondition(pcond);
			dir.in=pcond.in;
			string cond_content=qiparser::removespace(pcond.direction);
			string block_content=pcond.out;
			string while_block_content=pcond.out;
			//if cond==true then
			while(qiparser::parsecondition(cond_content)){
				//parse block_content:
				while_block_content=qiparser::parsehtml(block_content);
				//output content
				dir.out+=while_block_content;
			}
		}

        void _FOR(TemplateParser::BO::parsedirection &dir)
		{
			TemplateParser::BO::parsedirection pcond;
			pcond.in=dir.in;
			parseBlockNCondition(pcond);
			dir.in=pcond.in;
			string cond_content=qiparser::removespace(pcond.direction);
			string block_content=pcond.out;
			string for_block_content=pcond.out;


			//split cond to get param: 1-op, 2- condition, 3-op
			cond_content=qiparser::removeCurlyBracket(cond_content);
			vector< string > SplitVec; // #2: Search for tokens
			boost::split( SplitVec, cond_content, boost::is_any_of(";"),boost::algorithm::token_compress_on);
			if(SplitVec.size()<3){
				//throw error
				cerr<<"expect ; in \"for\""<<endl;
				return;
			}
			string op1=SplitVec[0];
			string cond=SplitVec[1];
			string op2=SplitVec[2];

			//do first op
			//get key
			string::size_type pos=string::npos;
			pos=op1.find_first_of('=');
			//cout<<op1<<"aaa"<<endl;
			if(pos!=string::npos){
				string key=op1.substr(0,pos);
				string value=op1.substr(pos,op1.size()-pos);
				//cout<<key<<'-'<<value<<endl;
				qiparser::parseEqualOperation(key,value);
			}

			//if cond==true then
			//cout<<cond<<"aaa"<<endl;
			while(qiparser::parsecondition(cond)){

				//parse block_content:
				for_block_content=qiparser::parsehtml(block_content);
				//output content
				dir.out+=for_block_content;
				//do op2
				string::size_type pos=string::npos;
				pos=op2.find_first_of('=');
				if(pos!=string::npos){
					string key=op2.substr(0,pos);
					string value=op2.substr(pos,op2.size()-pos);
					//cout<<key<<'-'<<value<<endl;
					qiparser::parseEqualOperation(key,value);
				}
			}
		}
*/

#endif
